#include "StdAfx.h"
#include ".\inifile.h"
static int etc_CopyAndLocate2 (FILE* etc_fp, FILE* tmp_fp, 
			const char* pSection, const char* pKey,char* pValue);

CIniFile::CIniFile(void)
{
}

CIniFile::~CIniFile(void)
{
}
void CIniFile::SetPath(CString Path)
{
	FilePath = Path;
}

BOOL CIniFile::OpenIniFileForRead()
{
	BOOL bExist=IniFile.Open(FilePath+FileName,CFile::modeRead); 
	return bExist;
}

BOOL CIniFile::OpenIniFileForWrite()
{
	BOOL bExist=IniFile.Open(FilePath+FileName,CFile::modeCreate | CFile::modeWrite);
	return bExist;
}

void CIniFile::CloseIniFile()
{
	IniFile.Close();
}

BOOL CIniFile::FindSection(CString Section)
{
	IniFile.SeekToBegin();
	CString str;
	BOOL bFind=FALSE;
	BOOL bEnd=IniFile.ReadString(str);
	while(!bFind && bEnd)
	{
		if(str.Find(Section)>=0)
		{
			bFind=TRUE;
			break;
		}
		bEnd=IniFile.ReadString(str);
	}
	return bFind;
}

BOOL CIniFile::WriteSection(CString Section)
{
	CFileStatus status;
	if(IniFile.GetStatus(status))
	{
		IniFile.WriteString("["+Section+"]\n");
		return TRUE;
	}
	else
		return FALSE;
}

BOOL CIniFile::WriteItemInt(CString Item, int Value)
{
	CFileStatus status;
	if(IniFile.GetStatus(status))
	{
		CString str;
		str.Format("%d",Value);
		str=Item+"="+str+"\n";
		IniFile.WriteString(str);
		return TRUE;
	}
	else
		return FALSE;
}

BOOL CIniFile::WriteItemString(CString Item, CString Value)
{
	CFileStatus status;
	if(IniFile.GetStatus(status))
	{
		IniFile.WriteString(Item+"="+Value+"\n");
		return TRUE;
	}
	else
		return FALSE;
}

BOOL CIniFile::GetItemInt(CString Section, CString Item, int &Value)
{
	CFileStatus status;
	if(IniFile.GetStatus(status))
	{
		if(FindSection(Section))
		{
			CString buf,sub;
			BOOL bFind=FALSE;
			BOOL bEnd=IniFile.ReadString(buf);
			while(!bFind && bEnd)
			{
				sub=buf.Left(buf.Find("="));
				if(buf.Find("[")<0 && !sub.IsEmpty() && sub.Find(Item)>=0)
				{
					sub=buf.Right(buf.GetLength()-buf.Find("=")-1);
					sub=GetValueString(sub);
					Value=atoi(sub);
					bFind=TRUE;
					break;
				}
				bEnd=IniFile.ReadString(buf);
			}
			return bFind;
		}
		else
			return FALSE;
	}
	else
		return FALSE;
}

BOOL CIniFile::GetItemString(CString Section, CString Item, CString &Value)
{
	CFileStatus status;
	if(IniFile.GetStatus(status))
	{
		if(FindSection(Section))
		{
			CString buf,sub;
			BOOL bFind=FALSE;
			BOOL bEnd=IniFile.ReadString(buf);
			while(!bFind && bEnd)
			{
				sub=buf.Left(buf.Find("="));
				if(buf.Find("[")<0 && !sub.IsEmpty() && sub.Find(Item)>=0)
				{
					sub=buf.Right(buf.GetLength()-buf.Find("=")-1);
					Value=GetValueString(sub);
					bFind=TRUE;
					break;
				}
				bEnd=IniFile.ReadString(buf);
			}
			return bFind;
		}
		else
			return FALSE;
	}
	else
		return FALSE;
}

CString CIniFile::GetValueString(CString str)
{
	int length=str.GetLength();
	BOOL bSpace=TRUE;
	while(length && bSpace)
	{
		if(str[0]==' ')
			str=str.Right(--length);
		else
			bSpace=FALSE;
	}
	bSpace=TRUE;
	while(length && bSpace)
	{
		if(str[length-1]==' ')
			str=str.Left(--length);
		else
			bSpace=FALSE;
	}
	return str;
}

BOOL CIniFile::WriteString(CString str)
{
	CFileStatus status;
	if(IniFile.GetStatus(status))
	{
		IniFile.WriteString(str);
		return TRUE;
	}
	else
		return FALSE;
}

void CIniFile::SetName(CString Name)
{
	FileName=Name+".ini";
}

static int etc_LocateSection(FILE* fp, const char* pSection, FILE* bak_fp)
{
	char szBuff[ETC_MAXLINE + 1];
	char* current;
	char* tail;

	while (TRUE) {
		if (!fgets(szBuff, ETC_MAXLINE, fp))
			return ETC_FILEIOFAILED;
		else if (bak_fp && fputs (szBuff, bak_fp) == EOF)
			return ETC_FILEIOFAILED;

		current = szBuff;

		while (*current == ' ' ||  *current == '\t') current++; 

		if (*current == ';' || *current == '#') continue;

		if (*current++ == '[') 
			while (*current == ' ' ||  *current == '\t') current ++;
		else
			continue;

		// Locate the tail.
		tail = current;
		while (*tail != ']' && *tail != '\n' &&
			*tail != ';' && *tail != '#' && *tail != '\0')
			tail++;
		*tail = '\0';
		while (*tail == ' ' || *tail == '\t') {
			*tail = '\0';
			tail--; 
		}

		if (strcmp (current, pSection) == 0)
			return ETC_OK; 
	}

	return ETC_SECTIONNOTFOUND;
}

// This function locate the specified key in the etc file.
static int etc_LocateKeyValue(FILE* fp, const char* pKey, 
							  BOOL bCurSection, char* pValue, int iLen,
							  FILE* bak_fp)
{
	char szBuff[ETC_MAXLINE + 1 + 1];
	char* current;
	char* tail;
	char* value;

	while (TRUE) {
		if (!fgets(szBuff, ETC_MAXLINE, fp))
			return ETC_FILEIOFAILED;
		if (szBuff [strlen (szBuff) - 1] == '\n')
			szBuff [strlen (szBuff) - 1] = '\0';
		current = szBuff;
		while (*current == ' ' ||  *current == '\t') current++; 

		if (*current == ';' || *current == '#') continue;

		if (*current == '[') {
			if (bCurSection) {
				if (!iLen) fprintf (bak_fp, "%s=%s\n", pKey, pValue);
				if (bak_fp && fprintf(bak_fp,"\n%s\n",szBuff) == EOF)
					return ETC_FILEIOFAILED;
				return ETC_KEYNOTFOUND; 
			}
			else
				continue;
		}

		tail = current;
		while (*tail != '=' && *tail != '\n' &&
			*tail != ';' && *tail != '#' && *tail != '\0')
			tail++;

		value = tail + 1;
		if (*tail != '=')
			*value = '\0'; 

		*tail-- = '\0';
		while (*tail == ' ' || *tail == '\t') {
			*tail = '\0';
			tail--; 
		}

		if (strcmp (current, pKey) == 0) {
			tail = value;
			while (*tail != '\n' && *tail != '\0') tail++;
			*tail = '\0'; 

			if (pValue)
				strncpy (pValue, value, iLen);

			return ETC_OK; 
		}
		else if (bak_fp && *current != '\0')
			fprintf (bak_fp, "%s=%s\n", current, value);
	}

	return ETC_KEYNOTFOUND;
}

/* Function: GetValueFromEtcFile(const char* pEtcFile, const char* pSection,
*                               const char* pKey, char* pValue, int iLen);
* Parameter:
*     pEtcFile: etc file path name.
*     pSection: Section name.
*     pKey:     Key name.
*     pValue:   The buffer will store the value of the key.
*     iLen:     The max length of value string.
* Return:
*     int               meaning
*     ETC_FILENOTFOUND           The etc file not found. 
*     ETC_SECTIONNOTFOUND        The section is not found. 
*     ETC_EKYNOTFOUND        The Key is not found.
*     ETC_OK            OK.
*/
int GetValueFromEtcFile(const char* pEtcFile, const char* pSection,
							   const char* pKey, char* pValue, int iLen)
{
	FILE* fp;
//	char szDir[MAX_PATH];
//	GetModuleFileName(NULL,szDir, MAX_PATH);
//	char* p = strrchr(szDir, '\\');
//	if (p)
//	{
//		*p = '\0';
//	}
//	strcat(szDir,"\\");
//	strcat(szDir,pEtcFile);

	if (!(fp = fopen(pEtcFile, "r")))
		return ETC_FILENOTFOUND;

	if (pSection)
		if (etc_LocateSection (fp, pSection, NULL) != ETC_OK) {
			fclose (fp);
			return ETC_SECTIONNOTFOUND;
		}

		if (etc_LocateKeyValue (fp, pKey, pSection != NULL, 
			pValue, iLen, NULL) != ETC_OK) {
				fclose (fp);
				return ETC_KEYNOTFOUND;
			}

			fclose (fp);
			return ETC_OK;
}

/* Function: GetIntValueFromEtcFile(const char* pEtcFile, const char* pSection,
*                               const char* pKey);
* Parameter:
*     pEtcFile: etc file path name.
*     pSection: Section name.
*     pKey:     Key name.
* Return:
*     int                      meaning
*     ETC_FILENOTFOUND             The etc file not found. 
*     ETC_SECTIONNOTFOUND          The section is not found. 
*     ETC_EKYNOTFOUND              The Key is not found.
*     ETC_OK                       OK.
*/
int GetIntValueFromEtcFile(const char* pEtcFile, const char* pSection,
								  const char* pKey, int* value)
{
	int ret;
	char szBuff [51];

	ret = GetValueFromEtcFile (pEtcFile, pSection, pKey, szBuff, 50);
	if (ret < 0)
		return ret;

	*value = atoi (szBuff);
	return ETC_OK;
}

static int etc_CopyAndLocate (FILE* etc_fp, FILE* tmp_fp, 
							  const char* pSection, const char* pKey)
{
	if (pSection && etc_LocateSection (etc_fp, pSection, tmp_fp) != ETC_OK)
		return ETC_SECTIONNOTFOUND;

	if (etc_LocateKeyValue (etc_fp, pKey, pSection != NULL, 
		NULL, 0, tmp_fp) != ETC_OK)
		return ETC_KEYNOTFOUND;

	return ETC_OK;
}
//add by suijz on 2008-07-02
static int etc_CopyAndLocate2 (FILE* etc_fp, FILE* tmp_fp, 
							  const char* pSection, const char* pKey,char* pValue)
{
	if (pSection && etc_LocateSection (etc_fp, pSection, tmp_fp) != ETC_OK)
		return ETC_SECTIONNOTFOUND;


	int iRet = etc_LocateKeyValue (etc_fp, pKey, pSection != NULL, 
		pValue, 0, tmp_fp);
	if (iRet != ETC_OK)
		return iRet;

	return ETC_OK;
}

static int etc_FileCopy (FILE* sf, FILE* df)
{
	char line [ETC_MAXLINE + 1];

	while (fgets (line, ETC_MAXLINE + 1, sf) != NULL)
		if (fputs (line, df) == EOF) {
			return ETC_FILEIOFAILED;
		}

		return ETC_OK;
}

/* Function: SetValueToEtcFile(const char* pEtcFile, const char* pSection,
*                               const char* pKey, char* pValue);
* Parameter:
*     pEtcFile: etc file path name.
*     pSection: Section name.
*     pKey:     Key name.
*     pValue:   Value.
* Return:
*     int                      meaning
*     ETC_FILENOTFOUND         The etc file not found.
*     ETC_TMPFILEFAILED        Create tmp file failure.
*     ETC_OK                   OK.
*/
int SetValueToEtcFile (const char* pEtcFile, const char* pSection,
							  const char* pKey, char* pValue)
{
	FILE* etc_fp;
	FILE* tmp_fp;
	int rc;
//	FILE* fp;
//	char szDir[MAX_PATH];
//	GetModuleFileName(NULL,szDir, MAX_PATH);
//	char* p = strrchr(szDir, '\\');
//	if (p)
//	{
//		*p = '\0';
//	}
//	strcat(szDir,"\\");
//	strcat(szDir,pEtcFile);

	if ((tmp_fp = tmpfile ()) == NULL)
		return ETC_TMPFILEFAILED;

	if (!(etc_fp = fopen (pEtcFile, "r+"))) {
		fclose (tmp_fp);
		if (!(etc_fp = fopen (pEtcFile, "w")))
			return ETC_FILEIOFAILED;
		fprintf (etc_fp, "[%s]\n", pSection);
		fprintf (etc_fp, "%s=%s\n", pKey, pValue);
		fclose (etc_fp);
		return ETC_OK;
	}


//	switch (etc_CopyAndLocate (etc_fp, tmp_fp, pSection, pKey)) {
	switch (etc_CopyAndLocate2 (etc_fp, tmp_fp, pSection, pKey,pValue)) {
	case ETC_SECTIONNOTFOUND:
		fprintf (tmp_fp, "\n[%s]\n", pSection);
		fprintf (tmp_fp, "%s=%s\n", pKey, pValue);
		break;
	case ETC_KEYNOTFOUND:
		break;

	case ETC_FILEIOFAILED:
	default:
		fprintf (tmp_fp, "%s=%s\n", pKey, pValue);
		break;
	}

	if ((rc = etc_FileCopy (etc_fp, tmp_fp)) != ETC_OK)
		goto error;

	// replace etc content with tmp file content
	// truncate etc content first
	fclose (etc_fp);
	if (!(etc_fp = fopen (pEtcFile, "w")))
		return ETC_FILEIOFAILED;

	rewind (tmp_fp);
	rc = etc_FileCopy (tmp_fp, etc_fp);

error:
	fclose (etc_fp);
	fclose (tmp_fp);
	return rc;
}

